#!/usr/bin/env/python

import socket
import select
import gobject
import threading
import gtk

import dp

class window:

	def __init__(self, user_instance, switchboard):
		self.user_instance = user_instance
		self.switchboard = switchboard
		

		self.window = gtk.Window()
		self.window.set_size_request(500, 500)
		self.window.set_title("Conversation - "+self.user_instance.nick)
		self.window.connect("destroy", self._quit)
		self.box = gtk.VBox(False, 0)
		self.to_send = ''
		self.typing = 0
		self.chat_list = gtk.TreeStore(gtk.gdk.Pixbuf,gobject.TYPE_STRING)
		self.chat_tree = gtk.TreeView(self.chat_list)
		self.online_img = self.chat_tree.render_icon(gtk.STOCK_YES, gtk.ICON_SIZE_DND)
		self.window.add(self.box)


	def _quit(self, window):
		self.window.destroy()
		self.switchboard._close_chat()

	def _chat_window(self):
		top_box = gtk.HBox(False, 0)

		add_box = gtk.VBox(False, 1)
		add_btn = gtk.Button("Invite")
		add_pb =  self.chat_tree.render_icon(gtk.STOCK_ADD, gtk.ICON_SIZE_BUTTON)
		add_img = gtk.Image()
		add_img.set_from_pixbuf(add_pb)
		add_btn.set_relief(gtk.RELIEF_NONE)
		add_box.pack_start(add_img, False, False, 0)
		add_box.pack_start(add_btn, False, False, 0)

		block_box = gtk.VBox(False, 1)
		block_pb =  self.chat_tree.render_icon(gtk.STOCK_STOP, gtk.ICON_SIZE_BUTTON)
		block_btn = gtk.Button("Block")
		block_btn.set_relief(gtk.RELIEF_NONE)
		block_img = gtk.Image()
		block_img.set_from_pixbuf(block_pb)
		block_btn.set_relief(gtk.RELIEF_NONE)
		block_box.pack_start(block_img, False, False, 0)
		block_box.pack_start(block_btn, False, False, 0)

		send_box = gtk.VBox(False, 1)
		send_pb =  self.chat_tree.render_icon(gtk.STOCK_GO_FORWARD, gtk.ICON_SIZE_BUTTON)
		send_btn = gtk.Button("Send")
		send_btn.set_relief(gtk.RELIEF_NONE)
		send_img = gtk.Image()
		send_img.set_from_pixbuf(send_pb)
		send_btn.set_relief(gtk.RELIEF_NONE)
		send_box.pack_start(send_img, False, False, 0)
		send_box.pack_start(send_btn, False, False, 0)


		dpbox = gtk.VBox(False, 1)
		dppb =  self.chat_tree.render_icon(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)
		dpbtn = gtk.Button("Display Pictures")
		dpbtn.set_relief(gtk.RELIEF_NONE)
		dpimg = gtk.Image()
		dpimg.set_from_pixbuf(dppb)
		dpbtn.set_relief(gtk.RELIEF_NONE)
		dpbox.pack_start(dpimg, False, False, 0)
		dpbox.pack_start(dpbtn, False, False, 0)

		top_box.pack_start(add_box, False, False, 10)
		top_box.pack_start(block_box, False, False, 10)
		top_box.pack_start(send_box, False, False, 10)
		top_box.pack_start(dpbox, False, False, 10)
		top_box.show()

		
		user_box = gtk.HBox(False, 5)

		nick_n = gtk.Label("To: "+self.user_instance.nick)
		email = gtk.Label("<"+self.user_instance.email+">")
		user_box.pack_start(nick_n, False, True, 0)
		user_box.pack_start(email, False, True, 0)
		user_box.show()
		
		table = gtk.TextTagTable()

		col = gtk.TreeViewColumn()
		render_pixbuf = gtk.CellRendererPixbuf()
		col.pack_start(render_pixbuf, expand=False)
		col.add_attribute(render_pixbuf, 'pixbuf', 0)
		render_text = gtk.CellRendererText()
		col.pack_start(render_text, expand=True)
		col.add_attribute(render_text, 'text', 1)
		self.chat_tree.append_column(col)
		scroll_w= gtk.ScrolledWindow()
		scroll_w.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		scroll_w.add(self.chat_tree)
		scroll_w.show()	

			
		bottom_box = gtk.HBox(False, 0)
		chg_font = gtk.Button("Font")
		chg_font.show()
		bottom_box.pack_start(chg_font, False, False, 0)
		bottom_box.show()

		self.enter_buffer = gtk.TextBuffer(table)
		self.enter_text = gtk.TextView(self.enter_buffer)
		self.enter_buffer.connect_after("insert-text", self._typing_text)
		self.enter_text.show()
		sc_w = gtk.ScrolledWindow()
		sc_w.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
		sc_w.set_size_request(400,40)
		sc_w.add(self.enter_text)
		sc_w.show()
		
		self.cw_statusbar = gtk.Statusbar()
		self.context_id = self.cw_statusbar.get_context_id("Statusbar")
		self.cw_statusbar.show()

		self.box.pack_start(top_box, False, True, 0)
		self.box.pack_start(user_box, False, True, 3)
		self.box.pack_start(scroll_w, True, True, 3)
		self.box.pack_start(bottom_box, False, True, 0)
		self.box.pack_start(sc_w, False, True, 0)
		self.box.pack_start(self.cw_statusbar, False, True, 0)


		self.window.show_all()

	def _typing_text(self,text_buf, text_iter, *args):
		end = text_buf.get_iter_at_mark(text_buf.get_insert())
		start = end.copy()
		start.backward_chars(args[1])
		if args[0] != "\n":
			self.to_send += args[0]
			if not self.typing:
				self.switchboard._typing_notification()
				self.typing = 1
		else:
			if self._send_text(self.to_send):
				self.to_send = ''
				self.typing = 0

		gtk.main_iteration()

	def _got_text(self, text):
		self.cw_statusbar.pop(self.context_id)
		self.chat_list.append(None, (self.online_img, ""+self.user_instance.nick+" says:\n"+text))


	def _send_text(self, text):
		if len(text) > 0:
			self.switchboard._send_text(text)
			self.enter_buffer.set_text('')
			self.chat_list.append(None, (self.online_img, ""+self.switchboard.my_email+" says:\n"+text))
			return True

class Session(threading.Thread):

	def __init__(self, my_email,sess_details=None, user_instance=None, initiator=0):
		threading.Thread.__init__(self)
		self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		self.tr_id = 0
		self.qng = 0
		self.my_email = my_email
		self.user = user_instance
		self.sess_details = sess_details
		self.initiator = initiator
		self.running = 0
		self.gui = window(user_instance, self)
		self.id = ''


	def _read_line(self):
		char = self.socket.recv(1)		
		prev_char = ''
		received_line = ''
		while char != "\n":
			received_line = received_line + char
			prev_char = char
			char = self.socket.recv(1)

		if char == "\n" and prev_char == "\r":
			received_line = received_line + char
			return received_line
		

	def _parse_sync(self, cmd, params=None):
		if params:
			command = cmd + ' ' + str(self.tr_id) + ' ' + params + '\r\n'
		else:
			command = cmd + ' ' + str(self.tr_id) + '\r\n'

		if self.socket.send(command):
			print ">> ", repr(command)
			self.tr_id += 1
			server_answer = self._read_line()
			if server_answer:
				print "<< ", repr(server_answer)
				return server_answer

	def _sync(self, command):
		if self.socket.send(command):
			print ">> ", repr(command)
			self.tr_id += 1
			server_answer = self._read_line()
			if server_answer:
				print "<< ", repr(server_answer)
				return server_answer

	def _show_gui(self):
		self.gui._chat_window()

	def _establish(self):
		xfr = self.sess_details[0]
		auth = self.sess_details[1]
		self.id = self.sess_details[2]
		self.socket.connect((xfr, 1863))
		data_in = self._parse_sync("ANS", ""+self.my_email+" "+auth+" "+self.id)

		#ugly.. receives the IRO's until we get an answer
		while data_in != "ANS":
			data_in = self._read_line().split(" ")[0]

		#Start the thread Here#
		return True

	def _create(self):
		xfr = self.sess_details[0]
		auth = self.sess_details[1]
		self.socket.connect((xfr, 1863))
		usr = self._parse_sync("USR", ""+self.my_email+" "+auth).split(" ")[0]
		if usr == "USR":
			return True
		else:
			return False

	def _invite(self, user_instance):
		self._parse_sync("CAL", ""+user_instance.email)
		joi = self._read_line().split(" ")[0]
		if joi == "JOI":
			self.gui.cw_statusbar.push(self.gui.context_id, "Opened Chat Session")
			return True
		else:
			return False
			
	def _invited(self):
		print "invited"
		if self._establish():
#			self._check_dp()
			self.running = 1	
			self.start()

	def _inviter(self):
		print "inviter"
		if self._create():
			self._invite(self.user)
			self.running = 1
			self.start()
		

	def run(self):
		gobject.timeout_add(500, self._watch_socket)

	def _watch_socket(self):
		if self.running:
			socket_descriptor = self.socket.fileno()
			r,w,e = select.select([socket_descriptor], [], [], 0)
			if len(r) > 0:
				buf = self._read_line()
				self._process_incoming(buf)
			else:
				print "nothing from chat with", self.user.email

		return True
		

	def _process_incoming(self,buf):
		"""Trigger is gobject.IO_IN"""
		command = buf.split(" ")[0]

		if command == "MSG":
			payload = int(buf.split(" ")[3][:-2])
			msg = self.socket.recv(payload)
			print "GOT MSG and payload is ",msg
			msg_type = msg.split("\r\n")[1].split(": ")[1]
			#just in case there is encoding or shit with the type
			msg_type = msg_type.split(" ")[0]
			if msg_type == "text/x-clientcaps":
				print "User send client details."

			elif msg_type == "text/x-msmsgscontrol":
				self.gui.cw_statusbar.push(self.gui.context_id,self.user.nick+" is typing...")

			elif msg_type == "text/plain;" or msg_type == "text/plain":
				text = msg.split("\r\n")[-1]
				self.gui._got_text(text)


		elif command == "BYE":
			self._close_chat()

		else:
			print buf

		return True


	def _typing_notification(self):
		msnlp = 'MIME-Version: 1.0\r\nContent-Type: text/x-msmsgscontrol\r\nTypingUser: '
		msnlp = msnlp +self.my_email+ '\r\n\r\n'
		payload = str(len(msnlp))
		total = 'MSG '+str(self.tr_id)+' A '+payload+'\r\n'+msnlp	
		self.socket.send(total)	

	def _send_text(self, text):
		msnlp = 'MIME-Version: 1.0\r\n' \
		'Content-Type: text/plain; charset=UTF-8\r\n' \
		'X-MMS-IM-Format: FN=MS%20Sans%20Serif; EF=; CO=0; CS=0; PF=0\r\n'\
		'\r\n'\
		''+text

		payload = str(len(msnlp))
		total = 'MSG '+str(self.tr_id)+' A '+payload+'\r\n'+msnlp
		num = self.socket.send(total)
		print "SENT:",num, "and total is", len(total)


	def _close_chat(self):
		print "CLosing chat"
		self.running = 0
		self.socket.send('OUT\r\n')
		self.socket.close()
		

	def _check_dp(self):
		if self.user.msn_object is not None:
			d_p = dp.Base("momsn@live.com", self.user, self)
			d_p.invitation()			

		
